#include <windows.h>
#include "Game.h"

#define GAME_NAME  L"Super Mario"
#define CLASS_NAME L"WinClass"
#define SCREEN_WIDTH 1280		
#define SCREEN_HEIGHT 720

Game::Game(HINSTANCE HInstance,int frameRate)
{
	d3d = NULL;
	d3ddv = NULL;
	BackBuffer = NULL;

	FrameRate = frameRate;
	hInstance = HInstance;

	Depth=24;
}

LRESULT CALLBACK Game::WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
	}
	return DefWindowProc(hWnd,message,wParam,lParam);
}

void Game::InitWindow()
{
	WNDCLASSEX wndClassEx;
	//ZeroMemory(&wndClassEx,sizeof(wndClassEx));

	wndClassEx.cbSize=sizeof(wndClassEx);
	wndClassEx.style =CS_HREDRAW | CS_VREDRAW;
	wndClassEx.lpfnWndProc=(WNDPROC)Game::WinProc;
	wndClassEx.hInstance=hInstance;
	wndClassEx.hCursor=LoadCursor(hInstance, IDC_ARROW);
	wndClassEx.hbrBackground=(HBRUSH)COLOR_WINDOW;
	wndClassEx.lpszClassName=CLASS_NAME;
	wndClassEx.cbClsExtra = 0;
	wndClassEx.cbWndExtra = 0;
	wndClassEx.hIcon = NULL;
	wndClassEx.lpszMenuName = NULL;
	wndClassEx.hIconSm = NULL;

	RegisterClassEx(&wndClassEx);

	hWnd=CreateWindowEx(NULL,
		CLASS_NAME,
		GAME_NAME,
		WS_OVERLAPPED,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		SCREEN_WIDTH,
		SCREEN_HEIGHT,
		NULL,
		NULL,
		hInstance,
		NULL);// use with multiple windows

	ShowWindow(hWnd,SW_SHOWNORMAL);
	UpdateWindow(hWnd);
}

void Game::InitDirectX()
{
	d3d=Direct3DCreate9(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp,sizeof(d3dpp));
	d3dpp.Windowed=true;
	d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow=hWnd;

	d3dpp.BackBufferFormat =  D3DFMT_X8R8G8B8; 
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferHeight = SCREEN_HEIGHT;
	d3dpp.BackBufferWidth = SCREEN_WIDTH;

	d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&d3ddv);
	if (d3ddv==NULL) 
	{
		OutputDebugStringA("Error");
	}

	d3ddv->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&BackBuffer);
}

void Game::Init()
{
	game_active = true;
	InitWindow();
	InitDirectX();
	Keyboard::GetInstance()->Initialize(hWnd,hInstance);
	InitGameWorld();
	LoadResources(d3ddv);
}
void Game::InitGameWorld(){}
void Game::ProcessKeyBoard()
{
	// Collect all key states first
	Keyboard::GetInstance()->GetDeviceState();

	if (Keyboard::GetInstance()->IsKeyDown(DIK_ESCAPE)) 
	{
		PostMessage(hWnd,WM_QUIT,0,0);
	}

	// Collect all buffered events
	DWORD dwElements = 1024;
	Keyboard::GetInstance()->dInputDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), Keyboard::GetInstance()->KeyEvents, &dwElements, 0 );

	// Scan through all data, check if the key is pressed or released
	for( DWORD i = 0; i < dwElements; i++ ) 
	{
		int KeyCode = Keyboard::GetInstance()->KeyEvents[i].dwOfs;
		int KeyState = Keyboard::GetInstance()->KeyEvents[i].dwData;
		if ( (KeyState & 0x80) > 0)
			OnKeyDown(KeyCode);
		else 
			OnKeyUp(KeyCode);
	}
}

void Game::Run()
{
	MSG msg;
	done=0;
	DWORD frame_start = GetTickCount();;
	DWORD tick_per_frame = 100 / FrameRate;

	while (done==0)
	{
		HRESULT hr = d3ddv->TestCooperativeLevel();
		if (hr == D3D_OK)
		{
			if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
			{
				if (msg.message==WM_QUIT) done = 1;

				TranslateMessage(&msg);
				DispatchMessage(&msg);			
			}
			if (game_active)
			{
				ProcessKeyBoard();
				ProcessInput(d3ddv);
				DWORD now = GetTickCount();
				DeltaTime = now - frame_start; 
				if (DeltaTime >= tick_per_frame)
				{
					frame_start = now;
					RenderAndUpdate();
				}
			}
		}
		/*
		if (hr == D3DERR_DEVICELOST)
		{
			game_active=false;
		}
		else if (hr == D3DERR_DEVICENOTRESET)
		{
			game_active=true;
			Keyboard::GetInstance()->Acquire();
		}*/
	}
}
	void Game::RenderAndUpdate()
	{
		if (d3ddv->BeginScene()) 
		{
			Update(DeltaTime);
			RenderFrame(d3ddv);
			d3ddv->EndScene();
		}
		d3ddv->Present(NULL,NULL,NULL,NULL);
	}
	void Game::Update(int Delta){}
	void Game::RenderFrame(LPDIRECT3DDEVICE9 d3ddv) {}
	void Game::LoadResources(LPDIRECT3DDEVICE9 d3ddv) { }
	void Game::ProcessInput(LPDIRECT3DDEVICE9 d3ddv) { }

	Game::~Game()
	{
		if (d3ddv!=NULL) d3ddv->Release();
		if (d3d!=NULL) d3d->Release();
		Keyboard::GetInstance()->~Keyboard();
	}

	void Game::OnKeyUp(int KeyCode) { }
	void Game::OnKeyDown(int KeyCode) { }

	int Game::GetScreenWidth(){
		return SCREEN_WIDTH;
	}
	int Game::GetScreenHeight(){
		return SCREEN_HEIGHT;
	}